[16-史上最快的日志库-zap]
一 Zap介绍
Zap 是Uber推出,非常快的、结构化的,分日志级别的 Go 日志库
无反射,零分配的JSON编码器,基本记录器尽可能避免序列化开销和分配
项目地址:https://github.com/uber-go/zap
官方文档:https://pkg.go.dev/go.uber.org/zap
Stars数量:20.3k
速度比较
二 快速使用
zap提供了两种日志记录器
go get -u go.uber.org/zap
2.1 SugaredLogger
加了糖的 Logger
在性能很好但不是很关键的环境中,使用SugaredLogger。它比其他结构化日志包快4-10倍,并且包含结构化和printf风格的api。
1 | package main |
2.2 Logger
当性能和类型安全至关重要时,使用Logger。它甚至比SugaredLogger还要快,并且分配的数量要少得多,但是它只支持结构化日志 。
1 | package main |
2.3 如何选择logger
在Logger和SugaredLogger之间进行选择不需要在应用程序范围内进行决定:在两者之间进行转换既简单又便宜。从上面就可以看出来,二者创建使用区别很小。
1 | package main |
2.4 日志级别
1 | //const 文档下面有介绍日志级别的定义,7个日志级别 |
三 高级使用
3.1 初始化 looger
在文档的 Configuring Zap中:
构建Logger最简单的方法是使用zap固有的预设:
NewExample,NewProduction和NewDevelopment
三者创建的 logger 是有区别的, 我们可以在官方文档的 type logger下面找到三个函数的介绍, 对应不同的场景。
NewExample
1 | func NewExample(options ...Option) *Logger |
NewProduction
1 | func NewProduction(options ...Option) (*Logger, error) |
NewDevelopment
1 | func NewDevelopment(options ...Option) (*Logger, error) |
3.2 方法使用
在文档的 types/logger 和 types/SaguredLogger 里面记录了相关的looger记录消息的使用方法
以 logger为例:
1 | //1 都接受一个 msg String, 后面是可选的一些字段。Field 类型,可以查看文档有很多的类型。 |
NewProduction
1 | package main |
注意
可以看到执行程序后终端提示相关的信心。 msg 就是自己设置的,时间, url等。 还有一个 caller 调用者信息,指明问题出现的行数
NewDevelopment()
创建的生成日志是这样的: 空格隔开, 缺少调用者
1 | 2022-05-02T16:01:00.202+0800 INFO go_test_learn/s20.go:21 访问博客成功 {"url": "https://www.cnblogs.com/liuqingzheng", "status": 200, "backoff": "3s"} |
NewExample()
1 | {"level":"info","msg":"访问博客成功","url":"https://www.cnblogs.com/liuqingzheng","status":200,"backoff":"3s"} |
3.3 定制 logger
查看NewProduction 的源码,实际底层就是: NewProductionConfig().Build(options…)
1 | func NewProduction(options ...Option) (*Logger, error) { |
观察New方法 生成logger 所需要的东西。在Build 函数中:
1 | // 返回一个 Core对象, 需要的是三个参数 |
关于 NewProductionConfig()函数, 返回对应的Config 对象,Build 函数根据这个配置,进行生成 logger对象。
我们可以自定义这个, 来实现生成自己的logger下面看下它的源码
1 | // NewProductionConfig是一个合理的生产日志配置。 |
写入文件
方式一
按照上面的自定义 logger, 创建核心Core需要三个参数,其中就有控制 写入文件的
Encoder: 编辑器。提供了两种信息的编辑方式
WriteSyncer:
指定日志写到哪里
。可以定义自己指定的文件路径通过func AddSync(w io.Writer) WriteSyncer 方法,返回一个。
AddSync用于转换io。Writer到WriteSyncer。它是智能的:Writer实现了WriteSyncer,我们将使用现有的Sync方法。如果没有,我们将添加一个无操作同步。1
2
3
4
5// 创建文件对象
file, _ := os.Create("./getLog.log") // 或者是用 OpenFile函数,在原来基础上追加。
// file, _ := os.OpenFile("./getLog.log", os.O_APPEND | os.O_RDWR, 0744)
// 生成 WriteSyncer
wSy := zapcore.AddSync(file)
LevelEnabler:
设置哪种级别的日志将被写入
- 对应的就是前面介绍的日志级别;如:
zapcore.DebugLevel
- 对应的就是前面介绍的日志级别;如:
创建自定义logger:
根据上面三点参数的理解,就可以指定文件建立了
```go
// 还剩一个后面的配置信息没有传入,但是已经可以了
// 默认我们调用 NewProduction()方法也是没有传递啥配置进去的。
log := New(
zapcore.NewCore(传递编辑器(两种), 自定义文件输出, cfg.Level(级别)),
)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
- 按照这样的建立完成之后就可以使用了,往指定文件里打印日志。
```go
func initLogger2() *zap.Logger {
//1 日志输出路径
//file, _ := os.Create("./test2.log")
file, _ := os.OpenFile("./test2.log", os.O_APPEND | os.O_RDWR, 0744)
// 把文件对象做成WriteSyncer类型
writeSyncer := zapcore.AddSync(file)
// 2 encoder编码,就两种
//encoder := zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig())
encoder := zapcore.NewConsoleEncoder(zap.NewProductionEncoderConfig())
// 3 创建core对象,指定encoder编码,WriteSyncer对象和日志级别
core := zapcore.NewCore(encoder, writeSyncer, zapcore.DebugLevel)
// 4 创建logger对象
logger := zap.New(core)
return logger
}
方式二
还有 zap 预置的生成 logger的方式,都是通过 NewProductionConfig() 来生成相关配置的, 自定义一个 NewProductionConfig() 然后,按着相应的步骤就可以了。 Build方法 就是通过 配置的 Config 对象,来生成的 logger。
重写方法,只需要加个文件名就可以了
1
2
3
4
5
6
7
8
9
10
11
12func initLogger() *zap.Logger {
// 1 得到config对象
conf := zap.NewProductionConfig()
// 2 修改config对象的属性,如编码,输出路径等
//conf.Encoding="console"
conf.Encoding = "json"
//conf.OutputPaths = append(conf.OutputPaths, "./test.log")
conf.OutputPaths = []string{"./test.log"}
//3 通过config对象得到logger对象指针
logger, _ := conf.Build()
return logger
}
更改时间编码
方式一
1 | func initLogger() *zap.Logger { |
方式二
1 | func initLogger2() *zap.Logger { |
增加调用者信息
根据时间的理解, 这里很容易想到: 配置项当中的 EncodeCaller, 也可以指定相关的函数,用来打印 调用者的信息。
方式一(该方式本身就有,不需要再加)
1 | func initLogger() *zap.Logger { |
还有一种方式是: 我们创建Core, zap.New()创建 logger, 分析第二个参数的 Options 类型, 文档中可以找到相关的方法,就有添加调试 显示调用人信息的方法。
方式二
1 | func initLogger2() *zap.Logger { |
四 使用 Lumberjack 进行日志切割归档
Zap 本身不支持切割归档日志文件,为了添加日志切割归档功能,我们将使用第三方库 Lumberjack 来实现。
1 | go get -u github.com/natefinch/lumberjack |
lumberjack.Logger 实现了 io.writer 接口,可以作为参数。
1 | func getLogWriter() zapcore.WriteSyncer { |
4.1 代码案例
1 | package main |
五 Gin中使用zap日志库
5.1 使用第三方库
1 | // 地址:https://github.com/gin-contrib/zap |
5.2 自己定制
讲解了 gin.Default 创建引擎, 默认的添加了两个中间件。 一个是 logger 日志,一个是 recover 恢复。 gin 自带的 logger 就是在这里实现起作用的
那么我们也需要将 zap封装为中间件–>GinLogger和GinRecovery
logger/logger.go
1 | package logger |
main.go
1 | package main |
点击上方按钮,请我喝杯咖啡!
扫描二维码,分享此文章